home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 February: Tool Chest / Apple Developer CD Series Tool Chest February 1996 (Apple Computer)(1996).iso / Sample Code / RAMDisk 1.2 / Sources / RamINIT.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-07-19  |  23.3 KB  |  842 lines  |  [TEXT/MPS ]

  1. #define __DebugVersion    1
  2. /*
  3. **    Apple Macintosh Developer Technical Support
  4. **
  5. **    RAMInit.c: An INIT which installs DRVR for RamDisk
  6. **
  7. **    by Gordon Sheridan and Jim Luther
  8. **  modified incessantly by Brian Bechtel
  9. **
  10. **    File:        RamINIT.c
  11. **
  12. **    Copyright © 1992-1995 Apple Computer, Inc.
  13. **    All rights reserved.
  14. **
  15. **    You may incorporate this sample code into your applications without
  16. **    restriction, though the sample code has been provided "AS IS" and the
  17. **    responsibility for its operation is 100% yours.  However, what you are
  18. **    not permitted to do is to redistribute the source as "DTS Sample Code"
  19. **    after having made changes. If you're going to re-distribute the source,
  20. **    we require that you make it clear in the source that the code was
  21. **    descended from Apple Sample Code, but that you've made changes.
  22. **
  23. **    Change History (most recent first):
  24. **
  25. **    Change History (most recent first):
  26. **
  27. **        <1.2>    07/03/95    BL°B    Many changes for Universal Header 2.0 
  28. **                                    compliance.  Changed how we install driver.
  29. **                                    Other bug fixes. See "Changes in 1.2" for
  30. **                                    details.
  31. **         <7>    06/10/94    BL°B    Explicitly set zone to system zone before
  32. **                                    getting the DRVR resource.  Symantec 7.0
  33. **                                    doesn't set the System attribute on the DRVR
  34. **                                    resource.  This can be hard to track down.
  35. **         <6>    05/19/94    BL°B    Modified debugger macros to avoid use of ANSI
  36. **                                     routines, and weird c-string dependencies.
  37. **         <5>    10/15/93    JML        Added code to resize unit table if needed.
  38. **         <4>    10/14/93    JML        Implement AddDebuggerLabels routine for MacsBug.
  39. **                                     Added Panic debug macros.
  40. **         <3>     6/29/93    gs        Change AddDriveToQueue to start with drive number 5.
  41. **         <2>     6/28/93    gs        Change _DebugVersion to __DebugVersion
  42. **         <1>     6/13/93    gs        Implement AddDebuggerLabels routine for TMON.
  43. **         <0>     4/17/92    gs        Clean up for Sample Code release.
  44. **/
  45.  
  46. #include "RamDisk.h"
  47.  
  48. #ifdef __DebugVersion
  49.     #include <string.h>
  50.     #include <TextUtils.h>
  51. #endif
  52.  
  53. /*****************************************************************************/
  54.  
  55. /*
  56. **    Prototypes
  57. */
  58.  
  59. pascal    void    ShowIcon7(short iconId, Boolean advance);
  60. pascal    short    AddMyDrive (long size,short driveRef);    /* returns drive number */
  61. pascal    OSErr    DRVRInstall (Handle,short);
  62. pascal    OSErr    DRVRRemove (short);
  63. pascal    OSErr    InstallGlue (Handle,short);
  64.  
  65. void    main (void);
  66. OSErr    InitializeGlobals (DrvrGlobals *driverGlobals);
  67. Ptr        GetUnitTableBase (void);
  68. void    SetUnitTableBase (Ptr newUnitTableBase);
  69. short    GetUnitEntryCount (void);
  70. void    SetUnitEntryCount (short newUnitEntryCount);
  71. OSErr    GrowUnitTable (void);
  72. short    GetUnusedDrvrRefNum (void);
  73. OSErr    GetDrvrRefNum (short *drvrRefNum);
  74. OSErr    MyDriverInstall (Ptr drvrPtr, short drvrRefNum);
  75. void    MyDriverRemove (short drvrRefNum);
  76. OSErr    AddDriveToQueue (long size, short drvrRef, short *driveNum);
  77. OSErr    RemoveDrive (short driveNum, DrvQElPtr *drivePtr);
  78.  
  79. #ifdef    __DebugVersion
  80.     short        NumToolboxTraps (void);
  81.     TrapType    GetTrapType (short theTrap);
  82.     Boolean        TrapAvailable (short theTrap);
  83.     void        AddDebuggerLabels (DrvrGlobals driverGlobals);
  84. #endif    __DebugVersion
  85.  
  86. /*****************************************************************************/
  87.  
  88. /*
  89. **    main
  90. */
  91.  
  92. void    main (void)
  93. {
  94.     DrvrGlobals    driverGlobals;
  95.     short        csParam[11];
  96.     short        drvrRefNum = 0;
  97.     short        driveNum = 0;
  98.     DrvQElPtr    driveQElPtr;
  99.     OSErr        result;
  100.     AuxDCEPtr    dcePtr;
  101.     Handle        driverHandle = nil;
  102.     char        handleState;
  103.  
  104. #ifdef THINK_C
  105.     RememberA0();
  106.     SetUpA4();
  107. #endif
  108. #ifdef __MWERKS__
  109.     long oldA4=SetCurrentA4();
  110. #endif
  111.  
  112.     
  113.     Panic("\pStarting RAMDisk");
  114.     ShowIcon7(rLoadOKIcon,false);    /* show OK icon to indicate we're executing */
  115.     
  116.     result = InitializeGlobals(&driverGlobals);
  117.     if (result != noErr)
  118.     {
  119.         Panic("\pCould not initialize globals");
  120.         goto Done;
  121.     }
  122.  
  123.     driverGlobals.ramDisk = NewPtrSysClear(driverGlobals.ramSize);
  124.     if (driverGlobals.ramDisk == nil)
  125.     {
  126.         Panic("\pNewSysPtr = nil");
  127.         result = memFullErr;
  128.         goto Done;
  129.     }
  130.  
  131. #ifdef    __DebugVersion
  132.     AddDebuggerLabels(driverGlobals);
  133. #endif    __DebugVersion
  134.     
  135.     result = GetDrvrRefNum(&drvrRefNum);
  136.     if (result != noErr)
  137.     {
  138.         Panic("\pGetDrvrRefNum failed!");
  139.         goto Done;
  140.     }
  141.     
  142.     SetZone(SystemZone());            /* <7> */
  143.  
  144.     driverHandle = Get1NamedResource(kDRVRType, kDriverName);
  145.     result = ResError();
  146.     if (result != noErr)
  147.     {
  148.         Panic("\pGet1NamedResource failed!");
  149.         goto Done;
  150.     }
  151.     
  152.     HLock(driverHandle);
  153.     DetachResource(driverHandle);
  154.     result = ResError();
  155.     if (result != noErr)
  156.     {
  157.         Panic("\pDetachResource failed!");
  158.         goto Done;
  159.     }
  160.     
  161.     SetZone(ApplicZone());            /* <7> */
  162.  
  163.     result = MyDriverInstall(*driverHandle, drvrRefNum);
  164.     if (result != noErr)
  165.     {
  166.         Panic("\pMyDriverInstall failed!");
  167.         goto Done;
  168.     }
  169.     
  170.     result = OpenDriver(kDriverName, &drvrRefNum);
  171.     if (result != noErr)
  172.     {
  173.         Panic("\pOpenDriver failed");
  174.         goto Done;
  175.     }
  176.     
  177.     /* put in drive queue */
  178.     result = AddDriveToQueue (driverGlobals.ramSize / 512, drvrRefNum, &driveNum);
  179.     if (result != noErr)
  180.     {
  181.         Panic("\pAddMyDrive returned negative driveNum!");
  182.         goto Done;
  183.     }
  184.     /* driveNum now = drive number */
  185.     
  186.     /*    Save driveNum in our globals so driver code can verify drive number in
  187.         Prime, Status and Control calls (if need be). The driver also checks 
  188.         driveNum in the driver globals for a non-zero value before accepting
  189.         regular prime, control and status calls. */
  190.     driverGlobals.driveNumber = driveNum;
  191.  
  192.     /* set drivers globals */
  193.     *(Ptr *)csParam = (Ptr)&driverGlobals;
  194.     result = Control(drvrRefNum, setGlobalsCC, (Ptr)csParam);
  195.     if (result != noErr)
  196.     {
  197.         Panic("\pControl returned err");
  198.         goto Done;
  199.     }
  200.     
  201.     /* check to see if it got them */
  202.     result = Status(drvrRefNum, getGlobalsSC, (Ptr)csParam);
  203.     if ((result != noErr) || (driverGlobals.ramSize != *(long *)csParam))
  204.     {
  205.         Panic("\pStatus returned err");
  206.         goto Done;
  207.     }
  208.             
  209.     /* zero & mount */
  210.     result = DIZero(driveNum, driverGlobals.volumeName);
  211.     if (result != noErr)
  212.     {
  213.         Panic("\pDIZero returned err");
  214.         goto Done;
  215.     }
  216.     
  217. Done:
  218.     if (result == noErr)
  219.         ShowIcon7(rLoadOKIcon,true);    /* draw OK icon and move pen */
  220.     else
  221.     {
  222.         dcePtr = (AuxDCEPtr)GetDCtlEntry(drvrRefNum);
  223.         if (dcePtr != nil)
  224.             if ((*dcePtr).dCtlFlags & dOpened)
  225.             {
  226.                 /* Driver is open - close it */
  227.                 result = CloseDriver(drvrRefNum);
  228.                 if (result == noErr)
  229.                     /* If driver was closed, ramDisk memory was released! */
  230.                     driverGlobals.ramDisk = nil;
  231.             }
  232.         
  233.         if (driveNum != 0)
  234.         {
  235.             result = RemoveDrive(driveNum, &driveQElPtr);    /* ignore errors */
  236.             if (result == noErr)
  237.                 /* Dispose of the DrvQEl. Since it was allocated as a
  238.                     MyDrvQEl record, we have to subract 4 from the address */
  239.                 DisposePtr((Ptr)((Ptr)(driveQElPtr) - 4));
  240.         }
  241.             
  242.         if (drvrRefNum != 0)
  243.             MyDriverRemove (drvrRefNum);
  244.         
  245.         if (driverHandle != nil)
  246.         {
  247.             handleState = HGetState(driverHandle);
  248.             if (handleState & 0x20)                /* Is driverHandle a resource? */
  249.                 ReleaseResource(driverHandle);    /* yes, release it */
  250.             else
  251.                 DisposeHandle(driverHandle);    /* no, dispose it */
  252.         }
  253.         
  254.         if (driverGlobals.ramDisk != nil)
  255.             DisposePtr(driverGlobals.ramDisk);
  256.             
  257. #ifdef    __DebugVersion
  258. /* ••• Need to add routine to remove TMON/MacsBug debugging macros */
  259. #endif    __DebugVersion
  260.             
  261.         ShowIcon7(rLoadBadIcon,true);            /* draw bad load icon and move pen */
  262.     }
  263. #ifdef THINK_C
  264.     RestoreA4();
  265. #endif
  266. #ifdef __MWERKS__
  267.     SetA4(oldA4);
  268. #endif
  269. }
  270.  
  271. /*****************************************************************************/
  272.  
  273. /*
  274. **    InitializeGlobals
  275. **
  276. **    Initialize the globals using data read from resources. 
  277. */
  278.  
  279. OSErr    InitializeGlobals (DrvrGlobals *driverGlobals)
  280. {
  281.     OSErr            result = -1;
  282.     Handle            physicalIconHandle, mediaIconHandle;
  283.     ConfigRecHandle    configHandle;
  284.     long            length;
  285.  
  286.     driverGlobals->ramDisk = nil;    /* RAM disk memory isn't allocated yet */
  287.  
  288.     /* Get the user configuration, icons, and the "where" string */
  289.     configHandle = (ConfigRecHandle)Get1Resource ('RDcf', 0);
  290.     physicalIconHandle = Get1Resource('ICN#', rPhysicalIcon);
  291.     mediaIconHandle = Get1Resource('ICN#', rMediaIcon);
  292.     
  293.     if (configHandle && physicalIconHandle && mediaIconHandle)
  294.     {
  295.         /* See if we are supposed to install */
  296.         if ((**configHandle).install)
  297.         {            
  298.             /* Copy the user's preferred volume name to the driver globals. */
  299.             length = (**configHandle).volumeName[0]+1;
  300.             BlockMove((**configHandle).volumeName, driverGlobals->volumeName, length);
  301.             
  302.             /* Copy ICN# to driver globals so it has a physical location icon for volumes. */
  303.             BlockMove( &(**physicalIconHandle), (Ptr)(driverGlobals->physicalIcon), kLargeIconSize);
  304.             
  305.             /* Copy ICN# to driver globals so it has a default media icon for volumes. */
  306.             BlockMove( &(**mediaIconHandle), (Ptr)(driverGlobals->mediaIcon), kLargeIconSize);
  307.             
  308.             /* Put the drive location string into the driver globals. */
  309.             GetIndString(driverGlobals->locationStr, rStringList, rLocationStr);
  310.             if (ResError() != noErr)
  311.                 BlockMove("\pIn RAM", driverGlobals->locationStr, 7);
  312.                         
  313.             driverGlobals->ramSize = (**configHandle).size * 1024;
  314.             
  315.             result = noErr;
  316.         }
  317.     }
  318.     
  319.     if (configHandle)
  320.         ReleaseResource((Handle)configHandle);
  321.     if (physicalIconHandle)
  322.         ReleaseResource(physicalIconHandle);
  323.     if (mediaIconHandle)
  324.         ReleaseResource(mediaIconHandle);
  325.     
  326.     return (result);
  327. }
  328.  
  329. /*****************************************************************************/
  330.  
  331. /*
  332. **    GetUnitTableBase
  333. **    SetUnitTableBase
  334. **    GetUnitEntryCount
  335. **    SetUnitEntryCount
  336. **
  337. **    Functions to encapsulate access to the low-memory globals UTableBase and
  338. **    UnitNtryCnt.
  339. */
  340.  
  341. Ptr        GetUnitTableBase (void)
  342. {
  343.     return (LMGetUTableBase());
  344. }
  345.  
  346. void    SetUnitTableBase (Ptr newUnitTableBase)
  347. {
  348.     LMSetUTableBase(newUnitTableBase);
  349. }
  350.  
  351. //GetUnitEntryCount
  352. //1.2 Brian Bechtel
  353. // Changed to use new definition in Universal Headers
  354. short    GetUnitEntryCount (void)
  355. {
  356.     return (LMGetUnitTableEntryCount());
  357. }
  358.  
  359. //SetUnitEntryCount
  360. //1.2 Brian Bechtel
  361. // Changed to use new definition in Universal Headers
  362. void    SetUnitEntryCount (short newUnitEntryCount)
  363. {
  364.     LMSetUnitTableEntryCount(newUnitEntryCount);
  365. }
  366.  
  367. /*****************************************************************************/
  368.  
  369. /*
  370. **    GrowUnitTable
  371. **
  372. **    Allocates and switches to a larger unit table.  If the current unit table
  373. **    has less than kMinUnitNum entries, the unit table is increased to
  374. **    kMinUnitNum + 16.  If the current unit table has more than kMinUnitNum
  375. **    entries, the unit table is increased by 4 entries up to kMaxUTEntries.
  376. */
  377.  
  378. OSErr    GrowUnitTable (void)
  379. {
  380.     OSErr    result = noErr;
  381.     Ptr        oldUnitTableBase;
  382.     short    oldUnitEntryCount;
  383.     Ptr        newUnitTableBase;
  384.     short    newUnitEntryCount;
  385.     
  386.     oldUnitTableBase = GetUnitTableBase();
  387.     oldUnitEntryCount = GetUnitEntryCount();
  388.     
  389.     if (oldUnitEntryCount < kMinUnitNum)
  390.         newUnitEntryCount = 64;
  391.     else
  392.         newUnitEntryCount = oldUnitEntryCount + 4;
  393.     
  394.     if (newUnitEntryCount <= kMaxUTEntries)    /* The unit table cannot grow past kMaxUTEntries (128) */
  395.     {
  396.         /* Allocate the new unit table */
  397.         newUnitTableBase = NewPtrSysClear(newUnitEntryCount * sizeof(long));    // mike wiese
  398.         if (newUnitTableBase != nil)
  399.         {
  400.             /*    Copy the old unit table into the new. Although the 
  401.             **    "Driver Education" Tech Note says that you need to disable
  402.             **    interrupts around this operations, you don't. You only need to
  403.             **    perform the steps in the right order because anything that uses
  404.             **    the unit table at interrupt time shouldn't be saving the UTableBase
  405.             **    or UnitNtryCnt values between calls (if they do, they'll break even
  406.             **    if we do disable interrupts around these steps).
  407.             */
  408.         
  409.             /* First, copy the current unit table into the new unit table */
  410.             BlockMove(oldUnitTableBase, newUnitTableBase, oldUnitEntryCount * 4);
  411.         
  412.             /* Now, switch to the new unit table. After this step, the */
  413.             /* Device Manager will be using the new unit table. */
  414.             SetUnitTableBase(newUnitTableBase);
  415.         
  416.             /* Now, tell the system the table is larger. */
  417.             SetUnitEntryCount(newUnitEntryCount);
  418.         
  419.             /* Everything is switched, so we can get rid of the old unit table */
  420.             DisposPtr(oldUnitTableBase);
  421.         }
  422.         else
  423.         {
  424.             Panic("\pGrowUnitTable: New unit table could not be allocated");
  425.             result = unitTblFullErr;
  426.         }
  427.         
  428.     }
  429.     else
  430.     {
  431.         Panic("\pGrowUnitTable: Unit table cannot grow past kMaxUTEntries (128)");
  432.         result = unitTblFullErr;
  433.     }
  434.     
  435.     return (result);
  436. }
  437.  
  438. /*****************************************************************************/
  439.  
  440. /*
  441. **    GetUnusedDrvrRefNum
  442. **
  443. **    Finds the first unused unit table entry >= kMinUnitNum. Returns 0 if no
  444. **    unused entry is found.
  445. */
  446.  
  447. //1.2 Matthew E. Axsom
  448. // The problem occurs in the following lines of code:
  449. // 
  450. // >       while ((unitTable[unitNumber] != nil) && (unitNumber < unitEntryCount)) 
  451. // >               ++unitNumber;
  452. // >
  453. // >       if (unitTable[unitNumber] == nil)       /* Find an empty entry? */ 
  454. // >               /* Yes, then calculate its driver reference number */ 
  455. // >               drvrRefNum = -1 * (unitNumber +1);
  456. // 
  457. // The above code works just fine as long as the unit table has at least 1 empty 
  458. // slot in it.  If the unit table is completely full, i.e., no empty slots then 
  459. // this section of code can produce an invalid drvrRefNum.  I believe that if the 
  460. // table is full that the routine should return 0 (zero) and then grow the unit 
  461. // table and try again.  Instead, here's what can happen if the unit table is 
  462. // completely full:
  463. // 
  464. // If there are no empty slots in the unit table then eventually unitNumber will 
  465. // be >= unitEntryCount and the 'while' loop will terminate with unitNumber equal to
  466. // unitEntryCount.  Since there are only unitEntryCount-1 entries in the unit table, 
  467. // unitNumber now contains an "out of bounds" index for the unit table. After 
  468. // falling out of the 'while' loop, the 'if' statement then uses the "out of bounds" 
  469. // unitNumber for indexing into unitTable.  At this point if the address pointed 
  470. // to by unitTable[unitNumber] is nil then we get a "valid" drvrRefNum which is 
  471. // really invalid because unitNumber is "out of bounds".  What should happen is 
  472. // that the table is full and a drvrRefNum of 0 (zero) be returned so the unit 
  473. // table can be grown.
  474. // 
  475. // Since I needed to load a driver, I corrected the code this way:
  476. // 
  477. // >       while (unitNumber < unitEntryCount) {
  478. // >              if (unitTable[unitNumber] == nil) { /* Find an empty entry? */ 
  479. // >                       /* Yes, then calculate its driver reference number */ 
  480. // >                       drvrRefNum = -1 * (unitNumber +1);
  481. // >                       break;
  482. // >              }
  483. // >              else
  484. // >                       ++unitNumber;
  485. // >       }
  486. // 
  487. // I tested this out and, as far as I can tell, it works.  It correctly detects a 
  488. // full unit table and returns 0.  The calling routine then grows the unit table 
  489. // and tries again, this time with success.
  490. // 
  491.  
  492. short    GetUnusedDrvrRefNum (void)
  493. {
  494.     AuxDCEPtr    *unitTable;
  495.     short        unitEntryCount;
  496.     short        unitNumber;
  497.     short        drvrRefNum = 0;    /* default to no entry found */
  498.     
  499.     unitTable = (AuxDCEPtr *)GetUnitTableBase();
  500.     unitEntryCount = GetUnitEntryCount();
  501.     
  502.     /* Look for the first empty entry */
  503.     unitNumber = kMinUnitNum;
  504.     while (unitNumber < unitEntryCount) {
  505.         if (unitTable[unitNumber] == nil) { /* Find an empty entry? */ 
  506.             /* Yes, then calculate its driver reference number */ 
  507.             drvrRefNum = -1 * (unitNumber +1);
  508.             break;
  509.         }
  510.         else
  511.             ++unitNumber;
  512.     }
  513.     
  514.     return (drvrRefNum);
  515. }
  516.  
  517. /*****************************************************************************/
  518.  
  519. /*
  520. **    GetDrvrRefNum
  521. **
  522. **    Gets a reference number for our driver to use.  Grows the unit table if
  523. **    if is less than kMinUnitNum or if there are no empty entries in the
  524. **    unit table.
  525. */
  526.  
  527. OSErr GetDrvrRefNum (short *drvrRefNum)
  528. {
  529.     OSErr    result = noErr;
  530.     
  531.     *drvrRefNum = 0;
  532.     
  533.     /* See if we need to resize before we even look for an empty entry */
  534.     if (GetUnitEntryCount() < kMinUnitNum)
  535.         /* yep, so do it */
  536.         result = GrowUnitTable();
  537.     
  538.     if (result == noErr)
  539.     {
  540.         /* Find an unused driver reference number */
  541.         *drvrRefNum = GetUnusedDrvrRefNum();
  542.         if (*drvrRefNum == 0)
  543.         {
  544.             /* Didn't find one, so try growing the unit table one more time */
  545.             result = GrowUnitTable();
  546.             
  547.             if (result == noErr)
  548.                 /* Find an unused driver reference number */
  549.                 *drvrRefNum = GetUnusedDrvrRefNum();
  550.         }
  551.         if (*drvrRefNum == 0)
  552.             result = unitTblFullErr;
  553.     }
  554.     
  555.     return (result);
  556. }
  557.  
  558. /*****************************************************************************/
  559.  
  560. /*
  561. **    MyDriverInstall
  562. **
  563. **    Allocate a device control entry low in memory, initialize its dCtlDriver,
  564. **    dCtlFlags, and dCtlRefNum fields, and then add it to the unit table.
  565. */
  566. //1.2 John Wang
  567. // Instead of creating a AuxDCE record, we were creating a DCtlEntry.  
  568. // Because the record is smaller, the dCtlSlot field is garbage and 
  569. // causes _SUpdateSrt to be called when the driver is closed.
  570. OSErr    MyDriverInstall (Ptr drvrPtr, short drvrRefNum)
  571. {
  572.     OSErr            result = noErr;
  573.     short            unitNum;
  574.     AuxDCEHandle    *unitTable;
  575.     AuxDCEHandle    dceHandle;
  576.     
  577.     unitNum = -1 * (drvrRefNum + 1);
  578.     
  579.     unitTable = (AuxDCEHandle *)GetUnitTableBase();
  580.     
  581.     /* Make room as low as possible because the device control entry will */
  582.     /* be locked while the driver is open */
  583.     ResrvMem(sizeof(AuxDCE));
  584.     
  585.     dceHandle = (AuxDCEHandle)NewHandleSysClear(sizeof(AuxDCE));
  586.     if (dceHandle != nil)
  587.     {
  588.         HLock((Handle)dceHandle);        //<1.2>
  589.         (**dceHandle).dCtlDriver = drvrPtr;
  590.         (**dceHandle).dCtlFlags &= ~dRAMBased;    /* dRAMBased = dCtlDriver is handle */
  591.         (**dceHandle).dCtlRefNum = drvrRefNum;        
  592.  
  593.         /* Put dceHandle in the unit table */
  594.         unitTable[unitNum] = dceHandle;        
  595.     }
  596.     else
  597.     {
  598.         result = memFullErr;
  599.     }
  600.     
  601.     return (result);
  602. }
  603.  
  604. /*****************************************************************************/
  605.  
  606. /*
  607. **    MyDriverRemove
  608. **
  609. **    Used to remove a driver. The unit table entry is cleared, the driver
  610. **    handle is disposed, and the device control entry is disposed.
  611. */
  612.  
  613. void    MyDriverRemove (short drvrRefNum)
  614. {
  615.     short            unitNum;
  616.     AuxDCEHandle    *unitTable;
  617.     AuxDCEHandle    dceHandle;
  618.     
  619.     unitNum = -1 * (drvrRefNum + 1);
  620.     unitTable = (AuxDCEHandle *)GetUnitTableBase();
  621.  
  622.     if (unitNum > 0 && (unitNum <= kMaxUTEntries))
  623.     {
  624.         dceHandle = unitTable[unitNum];
  625.         if (dceHandle != nil)
  626.         {
  627.             /* Make sure the driver isn't open! */
  628.             if (((**dceHandle).dCtlFlags & dOpened) == 0)
  629.             {
  630.                 unitTable[unitNum] = nil;
  631. //1.2 Mike Wiese:
  632. // DriverRemove should not be disposing the driverhandle stored in dCltDriver,
  633. // since the install routine calls ReleaseResource or DisposHandle as appropriate.
  634. // Plus, if it's pointer based as it should be, disposeHandle won't work.
  635. //                if ((**dceHandle).dCtlDriver != nil)
  636. //                    DisposHandle((Handle)(**dceHandle).dCtlDriver);
  637.                 
  638.                 HUnlock((Handle)dceHandle);        //<1.2>
  639.                 DisposHandle((Handle)dceHandle);                
  640.             }
  641.         }
  642.     }
  643. }
  644.  
  645. /*****************************************************************************/
  646.  
  647. /*
  648. **    AddDriveToQueue
  649. **
  650. **    Find the first unused drive number greater than 4, allocate and initialize
  651. **    a drive queue element (including the drive flags), and add the drive queue
  652. **    element to the drive queue.
  653. */
  654.  
  655. OSErr    AddDriveToQueue (long size, short drvrRef, short *driveNum)
  656. {
  657.     OSErr        result = noErr;
  658.     QHdrPtr        driveQHdr;
  659.     DrvQEl        *drivePtr;
  660.     MyDrvQElPtr    newDrivePtr;
  661.     Boolean        driveNumFound = false;
  662.  
  663.     
  664.     driveQHdr = GetDrvQHdr();
  665.     
  666.     /* find first free drive number */
  667.     *driveNum = 5;                                            /* drive numbers 1-4 are reserved */
  668.     while (! driveNumFound)
  669.     {
  670.         drivePtr = (DrvQEl *)driveQHdr->qHead;                /* get first drive */
  671.         while (drivePtr && *driveNum != drivePtr->dQDrive)    /* order of tests important! */
  672.             drivePtr = (DrvQEl *)drivePtr->qLink;            /* get next drive */
  673.         
  674.         if (drivePtr == nil)
  675.             driveNumFound = true;
  676.         else
  677.             ++(*driveNum);
  678.     }
  679.  
  680.     if (*driveNum > 0)    /* must be a positive short */
  681.     {
  682.         /* allocate new drive queue element */
  683.         newDrivePtr = (MyDrvQElPtr)NewPtrSysClear(sizeof(MyDrvQEl));            
  684.         if (newDrivePtr != nil)
  685.         {
  686.             newDrivePtr->flags        = 0x00080000;            /* non-ejectable, disk not locked */
  687.             newDrivePtr->qType        = 1;                    /* see IM vol.4 p.181 */
  688.             newDrivePtr->dQDrive    = *driveNum;            /* •• dQDrive and dQRefNum are filled */
  689.             newDrivePtr->dQRefNum    = drvrRef;                /* •• in by AddDrive */
  690.             newDrivePtr->dQFSID        = 0;                    /* HFS */
  691.             newDrivePtr->dQDrvSz    = size & 0x0000FFFF;    /* dQDrvSz  = LoWord of size */
  692.             newDrivePtr->dQDrvSz2    = size >> 16;            /* dQDrvSz2 = HiWord of size */
  693.             
  694.             AddDrive (drvrRef, *driveNum, (DrvQEl *)&newDrivePtr->qLink);
  695.         }
  696.         else
  697.             result = memFullErr;
  698.     }
  699.     else
  700.         /* more than 32768 drives!?! */
  701.         result = nsDrvErr;
  702.     
  703.     return (result);
  704. }
  705.  
  706. /*****************************************************************************/
  707.  
  708. /*
  709. **    RemoveDrive
  710. **
  711. **    Find the drive queue element for driveNum in the drive queue and Dequeue it.
  712. **    Return pointer to the drive queue element removed in *drivePtr.
  713. */
  714.  
  715. OSErr    RemoveDrive (short driveNum, DrvQElPtr *drivePtr)
  716. {
  717.     QHdrPtr        driveQHdr;
  718.  
  719.     driveQHdr = GetDrvQHdr();
  720.     *drivePtr = (DrvQEl *)driveQHdr->qHead;                    /* get first drive */
  721.     while (*drivePtr && (driveNum != (*drivePtr)->dQDrive))    /* order of tests important! */
  722.         *drivePtr = (DrvQEl *)(*drivePtr)->qLink;            /* get next drive */
  723.     
  724.     if (*drivePtr != nil)
  725.         return (Dequeue((QElemPtr)*drivePtr, driveQHdr));
  726.     else
  727.         return (nsDrvErr);
  728. }
  729.  
  730. /*****************************************************************************/
  731. /*****************************************************************************/
  732.  
  733. #ifdef    __DebugVersion
  734.  
  735. /*****************************************************************************/
  736.  
  737. short    NumToolboxTraps (void)
  738. {
  739.     if (NGetTrapAddress(_InitGraf, ToolTrap) == NGetTrapAddress(0xAA6E, ToolTrap) )
  740.         return (0x200);
  741.     else
  742.         return (0x400);
  743. }
  744.  
  745. /*****************************************************************************/
  746.  
  747. TrapType    GetTrapType (short theTrap)
  748. {
  749.     if (theTrap & 0x0800)
  750.         return (ToolTrap);
  751.     else
  752.         return (OSTrap);
  753. }
  754.  
  755. /*****************************************************************************/
  756.  
  757. Boolean    TrapAvailable (short theTrap)
  758. {
  759.     TrapType    tType;
  760.     
  761.     tType = GetTrapType(theTrap);
  762.     if (tType == ToolTrap)
  763.     {
  764.         theTrap = theTrap & 0x7FF;
  765.         if (theTrap >= NumToolboxTraps() )
  766.             theTrap = _Unimplemented;
  767.     }
  768.     
  769.     return (NGetTrapAddress(theTrap, tType) !=
  770.             NGetTrapAddress(_Unimplemented, ToolTrap) );
  771. }
  772.  
  773. /*****************************************************************************/
  774.  
  775. #define kMacsbugMacroStr    "\p;MC RamDisk 'DM #"
  776. #define kMacsbugMacroStr2    "\p';g"
  777.  
  778. #define kTMONMacroStr        "\p™AddLabel RamDisk,."
  779. #define kTMONMacroStr2        "\p,."
  780.  
  781. #define AddString(src, dst) {    BlockMove(&src[1], dst+i, src[0]); i += src[0]; }
  782.  
  783. /* Add TMON or MacsBug debugger macros for easy viewing of RamDisk */
  784. void    AddDebuggerLabels (DrvrGlobals driverGlobals)
  785. {
  786.     Str255        strbuf;
  787.     Str31        numstr;
  788.     long        tmonVal;
  789.     short        err;
  790.     Boolean     done = false;
  791.     SignedByte    debugFlags;
  792.     short        i;
  793.  
  794.     strbuf[0] = 0;
  795.     if (TrapAvailable(_Gestalt))    /* check for TMON */
  796.     {
  797.         err = Gestalt('TMON',&tmonVal);
  798.         if (err == 0)
  799.         {
  800.             /* Add TMON label */
  801.             i = 1;
  802.             AddString(kTMONMacroStr, strbuf);
  803.             NumToString((long)driverGlobals.ramDisk,numstr);
  804.             AddString(numstr, strbuf);
  805.             AddString(kTMONMacroStr2, strbuf);
  806.             NumToString(driverGlobals.ramSize,numstr);
  807.             AddString(numstr, strbuf);
  808.             strbuf[0] = i - 1;
  809.  
  810.             DebugStr(strbuf);
  811.             
  812.             done = true;
  813.         }
  814.     }
  815.     if (!done)    /* If TMON isn't installed, define a macro for MacsBug */
  816.     {
  817.         debugFlags = *(SignedByte *) 0x0BFF;
  818.         if (debugFlags == -1)
  819.             debugFlags = *(SignedByte *) 0x0120;
  820.         
  821.         if (debugFlags & 0x20)
  822.         {
  823.             /* Define MacsBug macro */
  824.             i = 1;
  825.             
  826.             AddString(kMacsbugMacroStr, strbuf);
  827.             NumToString((long)driverGlobals.ramDisk, numstr);
  828.             AddString(numstr, strbuf);
  829.             AddString(kMacsbugMacroStr2, strbuf);
  830.             strbuf[0] = i - 1;
  831.             
  832.             DebugStr(strbuf);
  833.         }
  834.     }
  835. }
  836.  
  837. /*****************************************************************************/
  838.  
  839. #endif    __DebugVersion
  840.  
  841. /*****************************************************************************/
  842.